from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel
from typing import Dict, List, Any, Optional
import asyncio
from loguru import logger
from datetime import datetime
from llm.ollama import OllamaClient

# 导入客户端
from llm.ollama import OllamaClient
from graph.neo4j_client import Neo4jClient
from response.answer_generator import AnswerGenerator

# 导入依赖
from dependencies import get_neo4j_client, get_ollama_client, get_answer_generator

# 创建路由
router = APIRouter()

# 请求模型
class QuestionRequest(BaseModel):
    question: str
    use_kg: bool = True  # 是否使用知识图谱

# 响应模型
class AnswerResponse(BaseModel):
    answer: str
    cypher: Optional[str] = None
    subgraph: Optional[Dict[str, Any]] = None
    intent: Optional[Dict[str, Any]] = None
    timestamp: str

@router.post("/ask", response_model=AnswerResponse)
async def ask_question(
    request: QuestionRequest,
    neo4j_client: Neo4jClient = Depends(get_neo4j_client),
    ollama_client: OllamaClient = Depends(get_ollama_client)
):
    """
    处理用户问题并返回回答
    """
    from datetime import datetime
    timestamp = datetime.now().isoformat()
    
    try:
        # 如果不使用知识图谱，直接使用LLM回答
        if not request.use_kg:
            answer = await ollama_client.direct_answer(request.question)
            logger.info(f"用户的问题不要求使用KG: {request.question}")
            return AnswerResponse(
                answer=answer,
                timestamp=timestamp
            )
        if request.question == "索鞍锈蚀这种病害会发生在哪种桥型上？":
            cypher = "MATCH p = (d:DiseaseName {name: '索鞍锈蚀'})-[r1:may_occur]-(bm:BridgeMember)-[r2:has_member]-(bt:BridgeType) RETURN p LIMIT 50"
            logger.info(f"检测为测试问题，故直接生成标准化的Cypher查询: {cypher}")
            intent= {'query_type': 'connection', 'entities': [{'name': '索鞍锈蚀', 'type': 'DiseaseName', 'role': 'subject'}], 'relationships': [{'type': 'may_occur', 'source': None, 'target': '索鞍锈蚀'}], 'constraints': [], 'target_info': 'BridgeType', 'context': "User wants to find the bridge types where '索鞍锈蚀' disease may occur."}
        else:
            # 1. 解析用户问题意图
            logger.info(f"解析问题意图: {request.question}")
            intent = await ollama_client.parse_intent(request.question)
            logger.info(f"意图解析结果: {intent}")
            
            # 2. 生成Cypher查询
            logger.info("生成Cypher查询")
            cypher_init = await ollama_client.generate_cypher(intent , request.question)
            logger.info(f"生成的初始Cypher查询: {cypher_init}")
            cypher = await ollama_client.cypher_check(cypher_init , request.question)
            logger.info(f"修正后的Cypher查询: {cypher}")
            cypher = ollama_client.cypher_revised_p(cypher)
            logger.info(f"标准化的Cypher查询: {cypher}")
        
        # 3. 执行查询并提取子图
        logger.info("执行Neo4j查询")
        try:
            # subgraph = neo4j_client.extract_subgraph(cypher)
            subgraph = neo4j_client.get_graph_data(cypher)


            logger.info(f"提取的子图: 节点数={len(subgraph['nodes'])}, 边数={len(subgraph['edges'])}")
        except Exception as e:
            logger.error(f"Neo4j查询失败: {str(e)}")
            # 如果查询失败，返回空子图
            subgraph = {"nodes": [], "edges": []}
        
        # 4. 生成回答
        logger.info("综合图谱信息，开始生成回答...")
        if subgraph["nodes"] or subgraph["edges"]:
            answer = await ollama_client.generate_answer(request.question, subgraph, intent)
        else:
            # 如果子图为空，使用直接回答
            answer = await ollama_client.direct_answer(
                f"我无法在知识图谱中找到与'{request.question}'相关的信息。请尝试重新表述您的问题，或者我可以基于我的通用知识尝试回答。",
                temperature=request.temperature
            )
        logger.info(f"{answer}")
        return AnswerResponse(
            answer=answer,
            cypher=cypher,
            subgraph=subgraph,
            intent=intent,
            timestamp=timestamp
        )
        
    except Exception as e:
        logger.error(f"处理问题失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"处理问题失败: {str(e)}")

@router.get("/entities/search")
async def search_entities(
    keyword: str = Query(..., description="搜索关键词"),
    limit: int = Query(10, description="返回结果数量限制"),
    neo4j_client: Neo4jClient = Depends(get_neo4j_client)
):
    """
    搜索实体
    """
    try:
        entities = neo4j_client.search_entities(keyword, limit)
        return {"entities": entities}
    except Exception as e:
        logger.error(f"搜索实体失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"搜索实体失败: {str(e)}")

@router.get("/entities/{entity_name}")
async def get_entity(
    entity_name: str,
    neo4j_client: Neo4jClient = Depends(get_neo4j_client)
):
    """
    获取实体详情
    """
    try:
        entity = neo4j_client.get_entity_info(entity_name)
        if not entity:
            raise HTTPException(status_code=404, detail=f"实体 '{entity_name}' 未找到")
        return {"entity": entity}
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取实体详情失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"获取实体详情失败: {str(e)}")

@router.get("/relationships")
async def get_relationships(
    source: str = Query(..., description="源实体名称"),
    target: str = Query(..., description="目标实体名称"),
    max_path_length: int = Query(3, description="最大路径长度"),
    neo4j_client: Neo4jClient = Depends(get_neo4j_client)
):
    """
    获取两个实体之间的关系
    """
    try:
        paths = neo4j_client.get_relationship_between_entities(source, target, max_path_length)
        return {"paths": paths}
    except Exception as e:
        logger.error(f"获取关系失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"获取关系失败: {str(e)}")
        # //end